using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace Super
{
	[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = false)]
	public class ButtonAttribute : PropertyAttribute
	{
		public string methodName;
		public float btnWidth;

		public ButtonAttribute(string methodName, float btnWidth = 100f)
		{
			this.methodName = methodName;
			this.btnWidth = btnWidth;
		}
	}

	/// <summary>
	///	表格基本信息
	/// </summary>
	public class ExcelTableInfo
	{
		public List<string> keys = new List<string>();          	//所有的key的字段
		public List<string> keyTypes = new List<string>();      	//所有key的类型
		public string[] remarks;									//所有的备注
		public string[] fieldNames;                            		//所有的字段名
		public string[] fieldTypes;                             	//所有的字段类型
		public int fieldNum;                                   		//字段数量
		public string nodeName;										//数据节点的类名
		public string tableName;                                	//SO类的类名
		public string scriptPath;									//数据类和SO类的存放路径
		public bool hasKey;                                     	//含有主键
		public string[][] data;                                 	//表格里面的数据
		public int row;                                         	//表格行数
		public int col;                                         	//表格列数
		public int ignoreRow;                                   	//忽略行数
		public int ignoreCol;                                   	//忽略列数
		public bool hasLang;                                    	//含有多语言
		public List<string> langFieldNames = new List<string>(); 	//多语言字段名
		public List<int> langFieldIndexs = new List<int>();			//多语言索引
		public string excelPath;									//Excel路径
	}

	/// <summary>
	/// Excel表格基本数据
	/// </summary>
	public class ExcelTableBase : ScriptableObject
	{
		public string[] fieldNames;
		public string[] fieldTypes;
		public string[] keys;
		public string[] keyTypes;
		public string excelPath;
	}

	/// <summary>
	/// Excel Table基类
	/// </summary>
	public class ExcelTableNodeBase
	{
		[HideInInspector]
		public string[] rowData;
		public virtual void SetValue(string[] rowData)
		{
			this.rowData = rowData;
		}

		public virtual void ValueBackFill()
		{

		}
	}

	/// <summary>
	/// 二叉树节点
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class BinaryTreeNode<T>
	{
		public T value;
		public int height;
		public BinaryTreeNode<T> left;
		public BinaryTreeNode<T> right;
		public BinaryTreeNode<T> parent;


		public BinaryTreeNode(T value, int height = 1)
		{
			this.value = value;
			this.height = height;
		}

		public BinaryTreeNode(BinaryTreeNode<T> parent,  T value, int height = 1)
		{
			this.parent = parent;
			this.value = value;
			this.height = height;
		}
	}

	/// <summary>
	/// 多叉树节点
	/// </summary>
	/// <typeparam name="T"></typeparam>
	public class MultiTreeNode<T> where T : IMultiTreeNode<T>
	{
		public T value;
		public int height;
		public List<object> keys = new List<object>();

		public string dictSerializeJson = "";
		private Dictionary<object, MultiTreeNode<T>> map = new Dictionary<object, MultiTreeNode<T>>();
		public Dictionary<object, MultiTreeNode<T>> Map
		{
			get
			{
				if (map == null)
				{
					if (!String.IsNullOrEmpty(dictSerializeJson))
					{
						map = JsonConvert.DeserializeObject<Dictionary<object, MultiTreeNode<T>>>(dictSerializeJson);
					}
					if (map == null)
					{
						map = new Dictionary<object, MultiTreeNode<T>>();
					}
				}
				return map;
			}
		}

		public MultiTreeNode(int height = 1)
		{
			this.height = height;
		}

		public MultiTreeNode(T value, int height = 1)
		{
			this.value = value;
			this.height = height;
		}
	}

	/// <summary>
	/// ʱ��ڵ�
	/// </summary>
	public class TimerNode : IComparable
	{
		
		public float endTime;
		public Action<TimerNode> endCallBack;

		public float interval;
		public float nextIntervalTime;
		public int intervalCallNum;
		public Action<TimerNode> intervalCallBack;

		public float originLeftTime;
		public float LeftTime => endTime - Time.time;

		public TimerNode(float leftTime, Action<TimerNode> endCallBack)
		{
			originLeftTime = leftTime;
			this.endCallBack = endCallBack;
			UpdateEndTime();
		}

		public TimerNode(float leftTime, float interval, Action<TimerNode> intervalCallBack)
		{
			originLeftTime = leftTime;
			this.interval = interval;
			this.intervalCallBack = intervalCallBack;
			this.endCallBack = intervalCallBack;
			UpdateIntervalEndTime();
			UpdateEndTime();
		}

		public TimerNode(float leftTime, float interval, Action<TimerNode> intervalCallBack, Action<TimerNode> endCallBack)
		{
			originLeftTime = leftTime;
			this.interval = interval;
			this.intervalCallBack = intervalCallBack;
			this.endCallBack = endCallBack;
			UpdateEndTime();
			UpdateIntervalEndTime();
		}

		public void UpdateEndTime()
		{
			this.endTime = Time.time + originLeftTime;
		}

		public void UpdateIntervalEndTime()
		{
			
			if (nextIntervalTime == 0)
			{
				nextIntervalTime = Time.time + interval;
			}
			else
			{
				nextIntervalTime += interval;
			}
		}
		
		private float GetNextCallTime()
		{
			if (interval == 0)
				return endTime;
			return Mathf.Min(nextIntervalTime, endTime);
		}

        public int CompareTo(object obj)
        {
			TimerNode other = (TimerNode)obj;
			float nextTimer = GetNextCallTime();
			float otherNextTimer = other.GetNextCallTime();
			return nextTimer.CompareTo(otherNextTimer);
        }
    }


	/// <summary>
	/// 游戏事件节点
	/// </summary>
	public struct GameEventNode
	{
		public Type GE_Type;        
		public int priority;        
	}

	public class RouteNode : IMultiTreeNode<RouteNode>
	{
		public string name;
		public List<object> keys = new List<object>();

		public RouteNode(string name, List<object> ints)
		{
			this.name = name;
			this.keys = ints;
		}

		public int GetSameKeyNum(MultiTreeNode<RouteNode> root, RouteNode value)
		{
			int index = 0;
			for (int i = 0; i < root.keys.Count; i++)
			{
				if (!root.keys[i].Equals(keys[i]))
					break;
				index++;
			}

			return index;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public bool CheckIfInsertNode(MultiTreeNode<RouteNode> root, RouteNode value)
		{
			int num = GetSameKeyNum(root, value);
			return num >= keys.Count;
		}

		/// <summary>
		/// 
		/// 
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public object GetMapKey(MultiTreeNode<RouteNode> root, RouteNode value)
		{
			int num = GetSameKeyNum(root, value);
			return keys[num];
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		public void UpdateNode(MultiTree<RouteNode> tree, MultiTreeNode<RouteNode> root, RouteNode value)
		{
			if (CheckIfInsertNode(root, value))
			{
				root.value = value;
				root.keys = value.keys;
			}
		}
	}


	/// <summary>
	/// 
	/// MultiTree<AABBNodeValueSample>
	/// </summary>
	public class AABB : IMultiTreeNode<AABB>
	{
		public Bounds Bound;
		public GameObject GO;
		public AABB(){ }
		public AABB(Bounds bound, GameObject gO)
		{
			Bound = bound;
			GO = gO;
		}

		/// <summary>
		///
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public MultiTreeNode<AABB> FindMinDis(MultiTreeNode<AABB> root, AABB value)
		{
			float minDic = 0, dis = 0;
			object minKey = null;
			foreach (var item in root.Map)
			{
				dis = value.Bound.SqrDistance(item.Value.value.Bound.center);
				if (dis < minDic || minKey == null)
				{
					minDic = dis;
					minKey = item.Key;
				}
			}
			return root.Map[minKey];
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public bool CheckIfInsertNode(MultiTreeNode<AABB> root, AABB value)
		{
			return root.value == null;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="root"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		public object GetMapKey(MultiTreeNode<AABB> root, AABB value)
		{
			if (root.Map.Count >= 4)
			{
				MultiTreeNode<AABB> minDisNode = FindMinDis(root, value);
				return minDisNode.keys.Last();
			}
			else
			{
				return root.Map.Count;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="tree"></param>
		/// <param name="root"></param>
		/// <param name="value"></param>
		public void UpdateNode(MultiTree<AABB> tree, MultiTreeNode<AABB> root, AABB value)
		{
			bool isLeaf = root.Map.Count == 0;
			if (isLeaf)
			{
				root.value = value;
			}
			else
			{
				if (root.value.GO != null)
				{
					AABB nodeValue = new AABB(root.value.Bound, root.value.GO);
					root.value.GO = null;
					tree.Insert(nodeValue);
				}
				foreach (var item in root.Map)
				{
					root.value.Bound.Encapsulate(item.Value.value.Bound);
				}
			}
		}
	}

	/// <summary>
	/// Excel导入信息节点
	/// </summary>
	[Serializable]
	public class ExcelNoteNode
	{
		public string excelPath;
		public List<string> SOPaths = new List<string>();       
		public List<string> nodeNames = new List<string>();   
		public List<string> tableNames = new List<string>();    
		public List<string> scriptPaths = new List<string>();    

		public ExcelNoteNode(string excelPath)
		{
			this.excelPath = excelPath;
		}
	}

	[Serializable]
	public class LangFileInfo
	{
		public string name;
		public bool isCustom;
		public string absolutePath;
		public string addr;
		private LangDataInfo data;
		public LangDataInfo Data
		{
			get
			{
				if (data == null)
				{
					if (isCustom)
					{
						data = LangUtil.GetDataInfoByPath(absolutePath);
					}
					else
					{
						data = LangUtil.GetDataInfoByAddr(addr);
					}
				}
				return data;
			}

		}
	}

	public class LangDataInfo
	{
		public HashSet<string> keys = new HashSet<string>();
		public Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
	}

	public class CombBtnRunInfo
	{
		public bool isRun1 = false;		//����һ�׶�
		public bool isRun2 = false;     //���ܶ��׶�
		public TimerNode timerNode;
	}

	public class FunBtnTwoInfo
	{
		public bool isPressed = false;
		public float holdTime = 0;
	}
	
	public class MouseInfo
	{
		public Vector2 curPos = Vector2.zero;
		public Vector2 prePos = Vector2.zero;
		public Vector2 offsetPos = Vector2.zero;
		public bool hasMoved = false;
		public bool isHold = false;
		public MouseKey holdKey = MouseKey.Left;
	}	
	
	public class ParseStrArgSetting
	{
		public bool isClearParenthesis = true;	//清除小括号
		public bool isClearSquareBrackets = true;	//清除方括号
	}
}
